﻿using ImportPlcPointPosition.Utils;
using Mapster;
using S7.Net;
using S7.Net.Types;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ZR.Model.Models.ProductionControl;

namespace ZR.DataCollection2.Core
{
    public class SieminDecoder
    {

        /// <summary>
        /// 解析数据类型
        /// </summary>
        public class DecodeValue
        {
           /// <summary>
           /// 当前数据的点位
           /// </summary>
            public CksPlcDataPosition Position { get; set; }
            /// <summary>
            /// 读取值
            /// </summary>
            public object Value { get; set; }
            /// <summary>
            /// 读取旧值
            /// </summary>
            public object OldValue {  get; set; }

            public bool IsChange { 
                get {

                    if (this.Position.ParseType.IsS7ArrayInteger())
                    {
                        try
                        {
                             var arr1 =Value.Adapt<List<int>>();
                            var arr2 = OldValue.Adapt<List<int>>();
                            for (int i = 0; i < arr1.Count; i++)
                            {
                                var a = arr1[i];
                                var b = arr2[i];
                                if (a != b)
                                    return true;
                            }
                            return false;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                    else if (this.Position.ParseType.IsS7ArrayString())
                    {
                        try
                        {
                            var arr1 = Value.Adapt<List<string>>();
                            var arr2 = OldValue.Adapt<List<string>>();
                            for (int i = 0; i < arr1.Count; i++)
                            {
                                var a = arr1[i];
                                var b = arr2[i];
                                if (!a.Equals(b))
                                    return true;
                            }
                            return false;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                    else if (this.Position.ParseType.IsS7ArrayReal())
                    {
                        try
                        {
                            var arr1 = Value.Adapt<List<decimal>>();
                            var arr2 = OldValue.Adapt<List<decimal>>();
                            for (int i = 0; i < arr1.Count; i++)
                            {
                                var a = arr1[i];
                                var b = arr2[i];
                                if (a != b)
                                    return true;
                            }
                            return false;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                    else if (this.Position.ParseType.IsS7ArrayChar())
                    {
                        try
                        {
                            var arr1 = Value.Adapt<List<char>>();
                            var arr2 = OldValue.Adapt<List<char>>();
                            for (int i = 0; i < arr1.Count; i++)
                            {
                                var a = arr1[i];
                                var b = arr2[i];
                                if (a != b)
                                    return true;
                            }
                            return false;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                    return ! (Value.ToString().Equals(OldValue.ToString() ));
                } 
            }

            public Plc plcSession { get; internal set; }
            /// <summary>
            /// 该点位关联的步骤需要操作的数据位置
            /// </summary>
            public List<CksPlcDataPosition> StepPositions { get; internal set; }
            /// <summary>
            /// 该订阅点关联数据块的全部点位
            /// 当前点位数据关联的数据源；批量读取数据块的缓存；
            /// </summary>
            public List<DecodeValue> AllValues { get; internal set; }
        }


        /// <summary>
        /// 相同DB块内的全部解析数据
        /// </summary>
        public List<DecodeValue> Values { get; set; }


        public SieminDecoder(List<CksPlcDataPosition> points)
        {
            Points = points;
            Values = new List<DecodeValue>();
            foreach (var point in points) {
                if (point.ParseType.ToLower().Equals("struct"))
                    continue;
                DecodeValue dv = new DecodeValue();
                if (point.ParseType.StartsWith("string"))  //构造时初始化默认值，避免首次运行异常触发
                    dv.Value = "";
                else
                    dv.Value = (int)0;
               
                dv.Position = point;
               
                Values.Add(dv);
            }
        }

        public List<CksPlcDataPosition> Points { get; }

        public List<DecodeValue> Decode(byte[] blockBytes)
        {
            foreach (var val in Values) {
                var point = val.Position;
                val.Position = point;
                val.OldValue = val.Value;

                try
                {
                    val.Value = SieminDecoder.SimpleDecode(blockBytes, point.BytePosition, point.ByteLength, point.ParseType);

                }
                catch (Exception ex)
                {

                    throw;
                }
            }
            return Values;
        }

        
        public static object SimpleDecode(byte[] bytes, decimal position,int count,string ParseType)
        {
            int startIndex = (int)position;
            int bitindex = (int)(position * 10) % 10;
            //ArraySegment<byte> bytes = new ArraySegment<byte>(blockBytes);
            //var buffer = bytes.Slice(startIndex, count).Reverse().ToArray(); //大小端问题，需要反转字节数组
            var lowerType = ParseType.ToLower();
            if (IsArrayType(lowerType,out int arraylenth,out string type2))
            {
                //数组暂时只处理 int
                if (type2.Equals("int") || type2.Equals("int16"))
                {
                    List<short> shorts = new List<short>();

                    try
                    {
                        for (int i = 0; i < arraylenth; i++)
                        {
                          
                            var val = DataConversion.GetInt16DataByBytes(bytes, startIndex);
                            startIndex += 2;  // int16偏移是2字节
                            shorts.Add(val);
                        }
                        return shorts;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if(type2.Equals("word"))
                {
                    try
                    {
                        List<ushort> shorts = new List<ushort>();
                        for (int i = 0; i < arraylenth; i++)
                        {

                            var val = DataConversion.GetWordDataByBytes(bytes, startIndex);
                            startIndex += 2;  // int16偏移是2字节
                            shorts.Add(val);
                        }
                        return shorts;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if (type2.Equals("char"))
                {
                    try
                    {
                        List<char> shorts = new List<char>();
                        for (int i = 0; i < arraylenth; i++)
                        {
                            var val = DataConversion.GetChar(bytes, startIndex);
                            startIndex += 1;  // 
                            shorts.Add((char)val);
                        }
                        return shorts;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if(type2.Equals("real"))
                {
                    List<decimal> decimals = new List<decimal>();
                    try
                    {
                        for (int i = 0; i < arraylenth; i++)
                        {

                            var val = DataConversion.GetFloatDataByBytes(bytes, startIndex);
                            startIndex += 4;  // real偏移是4字节
                            decimals.Add((decimal)val);
                        }
                        return decimals;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if (type2.StartsWith("string["))
                {
                    List<string> decimals = new List<string>();
                    try
                    {
                        for (int i = 0; i < arraylenth; i++)
                        {
                            int length = 0;
                            if (type2.Contains("string"))
                            {
                                length= Regex.Match(type2, "[0-9]+").Value.ObjToInt() + 2;
                            }

                            var val = DataConversion.GetStringDataByBytes(bytes, startIndex, length);
                            startIndex += length;  // real偏移是4字节
                            decimals.Add(val);
                        }
                        return decimals;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }


                return string.Empty; //数组占位暂时不解析
            }
            switch (ParseType.ToLower())
            {
                case "string":
                    return DataConversion.GetStringDataByBytes(bytes, startIndex, count);
                case "int16":
                    return DataConversion.GetInt16DataByBytes(bytes, startIndex);
                case "word":
                    return DataConversion.GetWordDataByBytes(bytes, startIndex);
                case "int32":
                    return DataConversion.GetInt32DataByBytes(bytes, startIndex);
                case "double":
                    return DataConversion.GetDoubleDataByBytes(bytes, startIndex);
                case "float":
                    return DataConversion.GetFloatDataByBytes(bytes, startIndex);
                case "bool":
                    return DataConversion.GetBit(bytes[startIndex], bitindex);
                case "char":
                    return DataConversion.GetChar(bytes, startIndex);
                case "array":
                    return string.Empty;
                case "dtl":
                    return DataConversion.GetDTL(bytes, startIndex);
                case "dt":
                    return DataConversion.GetDT(bytes, startIndex);
                default:
                    throw new NotImplementedException("未实现该数据类型的解析");
            }
        }

        public static bool IsArrayType(string ArrayType, out int arrayLenth, out string ParseType)
        {
            ParseType = "";
            arrayLenth = 0;
            var dataType = ArrayType.ToLower();
            if (dataType.StartsWith("array[") && dataType.Contains("of"))
            {
                //Array[0..63] of Word

                var matches = Regex.Matches(dataType, "[0-9]+");
                if (matches.Count == 2)
                {
                    var Start = matches[0].Value.ObjToInt();
                    var End = matches[1].Value.ObjToInt();
                    double sizelenth = End - Start + 1;
                    arrayLenth = (int)sizelenth;
                    var arrayType = dataType.Split(' ')[2];
                    sizelenth = arrayType switch
                    {
                        "bool" => GetBoolLenth(sizelenth),
                        "int" => sizelenth * 2,
                        "word" => sizelenth * 2,
                        "dword" => sizelenth * 4, //uint
                        "dint" => sizelenth * 4,
                        "real" => sizelenth * 4,
                        "lreal" => sizelenth * 8,
                        _ => sizelenth
                    };
                    ParseType = arrayType;
                    //

                    //
                    return true;
                }
                else if(matches.Count == 3 && dataType.Contains("of string"))
                {
                    var arrayType = dataType.Split(' ')[2];
                    ParseType = arrayType;
                    var Start = matches[0].Value.ObjToInt();
                    var End = matches[1].Value.ObjToInt();
                    decimal sizelenth = End - Start + 1;
                    arrayLenth = (int)sizelenth;

                    return true;
                }

            }
            return false;
        }

        private static double GetBoolLenth(double sizelenth)
        {
            int d = (int)(sizelenth / 8);
            var yu = sizelenth % 8;
            if (yu == 0)
                return d;
            return (double)d + (yu / 10);
        }




    }
}
